package com.dream.libxrec.encode.audio;

import android.media.MediaCodec;
import android.media.MediaFormat;
import android.os.Build;
import android.util.Log;
import java.nio.ByteBuffer;

public abstract class IAudioMediaCodecEncoder extends IAudioEncoder {

    protected MediaFormat mEncoderFormat = null;
    protected MediaCodec mEncoder = null;
    private MediaCodec.BufferInfo info = null;
    private final static String TAG = "AudioEncoder";
    private boolean mStop = true;

    public void start()
    {
        if(mEncoder == null)
        {
            //不支持该解码器
            return;
        }
        info = new MediaCodec.BufferInfo();
        mEncoder.configure(mEncoderFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        mEncoder.start();
        mStop = false;
    }

    @Override
    public boolean isRun() {
        return !mStop;
    }

    @Override
    public synchronized void stop()
    {
        mStop = true;
        try {
            if (mEncoder != null){
                mEncoder.stop();
                mEncoder = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void encode(byte[] pcm, int offset, int size) {
        encode(pcm,offset,size,System.nanoTime()/1000);
    }

    /**
     *
     * @param size PCM数据大小
     * @param buffer PCM数据
     */
    @Override
    public synchronized void encode(byte[] buffer,int offset,
                                    int size,long presentationTimeUs)
    {
        if(buffer != null && mEncoder != null)
        {
            int inputIndex = mEncoder.dequeueInputBuffer(0);
            if(inputIndex >= 0)
            {
                ByteBuffer byteBuffer = getInputBuffer(inputIndex);
                byteBuffer.clear();
                byteBuffer.put(buffer);
                mEncoder.queueInputBuffer(inputIndex, offset, size,
                        presentationTimeUs, 0);
            }
            int index = 0;

            do{
                index = mEncoder.dequeueOutputBuffer(info, 0);
                //编码后的信息会存储在info中

                if (index > 0) {
                    ByteBuffer byteBuffer = getOutputBuffer(index);
                    //将一帧数据回调
                    if (mCb != null) {
                        mCb.onFrame(byteBuffer, info);
                    }
                    //释放
                    mEncoder.releaseOutputBuffer(index, false);
                }else if(index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                    Log.d(TAG, "readOutputData: " + mEncoder.getOutputFormat());
                    if (mCb != null) {
                        mCb.onFormat(mEncoder.getOutputFormat());
                    }
                }

            }while (index > 0);
        }
    }

    private ByteBuffer getInputBuffer(int index) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            return mEncoder.getInputBuffer(index);
        } else {
            return mEncoder.getInputBuffers()[index];
        }
    }

    private ByteBuffer getOutputBuffer(int index) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            return mEncoder.getOutputBuffer(index);
        } else {
            return mEncoder.getOutputBuffers()[index];
        }
    }
}
